package com.clwl.supervise.superviseapp.util;


import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
/**
 * 节假日获取
 */
public class HolidayUtil {


    private static  RedisUtil redisUtil;

    /**
     * 获取某个日期距离当前日期的天数
     * @param startDate
     * @param endDate
     * @return
     */
    public static long getLastYearWorkdayDays(Date startDate , Date  endDate) {
        //获取此当前年份的工作日
        List<String> holidayList = null;
        try {
            holidayList = HolidayUtil.getYearHolidays(DateUtil.year(new Date()));
        } catch (Exception e) {
            holidayList = new ArrayList<>();
        }
        //获取参数日期与当前日期的间隔日期
        List<String> dateList = HolidayUtil.getTwoDateList(startDate,endDate);
        //所有日期排除节假日
        List<String> finalHolidayList = holidayList;
        return dateList.stream().filter(d -> !finalHolidayList.contains(d) ).count();
    }

    /**
     * 获取某个日期距离当前日期的天数
     * @param startDate
     * @param endDate
     * @return
     */
    public static long getLastYearWorkdayDays(Date startDate , Date  endDate,List<String> holidayList) {
        //获取参数日期与当前日期的间隔日期
        List<String> dateList = HolidayUtil.getTwoDateList(startDate,endDate);
        //所有日期排除节假日
        return dateList.stream().filter(d -> !holidayList.contains(d)).count();
    }

    /**
     * 获取某年的工作日
     * @param year  年份
     * @return
     */
    public static List<String> getYearHolidays(int  year) {
        String holidays = null;
        try {
            String rediskKey = "holiday_"+DateUtil.year(new Date());
            String  holidyString = redisUtil.get(rediskKey);
            //log.info("redis获取节假日信息:{}",holidyString);
            if(StringUtils.isNotBlank(holidyString) && JSONUtil.isJson(holidyString)){
                holidays = holidyString;
            } else {
                HttpResponse response = HttpRequest.get("https://cdn.jsdelivr.net/npm/holiday-calendar/data/CN/" + year + ".json").timeout(2000).setFollowRedirects(true).execute();
                if (response.getStatus() != 200) {
                    return new ArrayList<>();
                }
                holidays = response.body();
                //log.info("在线获取节假日信息:{}",holidays);
                redisUtil.set(rediskKey,holidays);
                //有效期一年
                redisUtil.setExpire(rediskKey,365, TimeUnit.DAYS);
            }
        } catch (Exception e) {
            return new ArrayList<>();
        }
        if(holidays == null || !JSONUtil.isJson(holidays)){
            return new ArrayList<>();
        }
        JSONObject jongHolidays = JSONUtil.parseObj(holidays);
        JSONArray dateArrays = jongHolidays.getJSONArray("dates");
        //节日日期
        List<String> HolidayDates = new ArrayList<>();
        for (int i = 0; i < dateArrays.size(); i++) {
            if(StringUtils.equals(dateArrays.getJSONObject(i).getStr("type"),"public_holiday")) {
                HolidayDates.add(dateArrays.getJSONObject(i).getStr("date"));
            }
        }
        //所有串休日期
        List<String> cxDates = new ArrayList<>();
        for (int i = 0; i < dateArrays.size(); i++) {
            if(StringUtils.equals(dateArrays.getJSONObject(i).getStr("type"),"transfer_workday")) {
                cxDates.add(dateArrays.getJSONObject(i).getStr("date"));
            }
        }
        //所有周六周日
        List<String> weekendList = HolidayUtil.calculateWeekends(DateUtil.year(new Date()));
        //将所有休息日合并
        HolidayDates.addAll(weekendList);
        //排除串休的日子
        return  HolidayDates.stream().filter(date->!cxDates.contains(date)).collect(Collectors.toList());

    }

    /**
     * 获取年份所有周末日期
     * @param year
     * @return
     */
    private static List<String> calculateWeekends(int year) {
        List<String> weekDays = new ArrayList<>();
        DateTime start = DateUtil.beginOfYear(DateUtil.parse(year + "-01-01"));
        DateTime end = DateUtil.endOfYear(start);
        List<DateTime> weekends = new ArrayList<>();
        DateTime current = start;
        // 遍历全年每一天
        if(current.before(end)) {
            while (current.isBeforeOrEquals(end)) {
                int dayOfWeek = current.dayOfWeek();
                if (dayOfWeek == 6 || dayOfWeek == 7) { // Hutool 中 6=周六，7=周日
                    weekDays.add(current.toString("yyyy-MM-dd")); // 格式化为字符串并添加到结果
                }
                current = current.offset(DateField.DAY_OF_YEAR, 1);
            }
        } else {
            while (current.isAfterOrEquals(end)) {
                int dayOfWeek = current.dayOfWeek();
                if (dayOfWeek == 6 || dayOfWeek == 7) { // Hutool 中 6=周六，7=周日
                    weekDays.add(current.toString("yyyy-MM-dd")); // 格式化为字符串并添加到结果
                }
                current = current.offset(DateField.DAY_OF_YEAR, -1);
            }
        }
        return weekDays;
    }


    /**
     * 获取两个日期间隔的日期
     * @param start
     * @param end
     * @return
     */
    private static List<String> getTwoDateList(Date  start,Date  end ) {
        List<String> weekDays = new ArrayList<>();
        List<DateTime> weekends = new ArrayList<>();
        if(start != null && end != null) {
            DateTime current = DateTime.of(start);
            if(current.before(end)) {
                //如果开始时间比结束时间小
                while (current.isBeforeOrEquals(end)) {
                    weekDays.add(current.toString("yyyy-MM-dd")); // 格式化为字符串并添加到结果
                    current = current.offset(DateField.DAY_OF_YEAR, 1);
                }
            } else {
                //如果开始时间比结束时间大的话
                while (current.isAfterOrEquals(end)) {
                    weekDays.add(current.toString("yyyy-MM-dd")); // 格式化为字符串并添加到结果
                    current = current.offset(DateField.DAY_OF_YEAR, -1);
                }
            }
        }
        return weekDays;
    }

    @Resource
    public void setRedisUtil(RedisUtil redisUtil) {
        HolidayUtil.redisUtil = redisUtil;
    }
}
